package limiter;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author dushougudu
 */
public class FixedWindowLimiter {

    private volatile long lastRequestTime;
    private volatile long windowUnit;
    private volatile int counter;
    private volatile int threshold;

    public FixedWindowLimiter(long windowUnit, int threshold) {
        this.windowUnit = windowUnit;
        this.threshold = threshold;
    }

    /**
     * 固定窗口时间算法
     *
     * @return
     */
    public synchronized boolean fixedWindowsTryAcquire() {
        long currentTime = System.currentTimeMillis();
        //检查是否在时间窗口内
        if (currentTime - lastRequestTime > windowUnit) {
            // 计数器清0
            counter = 0;
            //开启新的时间窗口
            lastRequestTime = currentTime;
        }
        // 小于阀值
        if (counter < threshold) {
            counter++;  //计数器加1
            return true;
        }

        return false;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FixedWindowLimiter fixedWindowLimiter = new FixedWindowLimiter(1000, 5);

        CyclicBarrier barrier = new CyclicBarrier(5);
        List<CompletableFuture<Boolean>> list = new ArrayList<>();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
        for (int i = 0; i < 10; i++) {
            if (i == 5) {
                Thread.sleep(1000);
            }
            CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
                try {
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                boolean flag = fixedWindowLimiter.fixedWindowsTryAcquire();
                return flag;
            }, executor);
            list.add(future);
        }

        for (CompletableFuture<Boolean> future : list) {
            System.out.println(future.get());
        }

        executor.shutdown();
    }

}
